use num_traits::FromPrimitive;
use serde::{Deserialize, Serialize};
use std::{collections::HashMap, str::FromStr};

#[derive(Clone, Debug, Deserialize, Serialize, PartialEq)]
#[serde(untagged)]
pub enum Data {
    String(String),
    Number(f64),
    Bool(bool),
    List(Vec<Data>),
    Object(HashMap<String, Data>),
}

impl Data {
    pub fn str(&self) -> Option<&str> {
        match self {
            Data::String(str) => Some(str.as_str()),
            _ => None,
        }
    }
    pub fn num(&self) -> Option<f64> {
        match self {
            Data::Number(num) => Some(*num),
            _ => None,
        }
    }
    pub fn add_list(&mut self, v: &Data) {
        if let Data::List(list) = self {
            list.push(v.clone())
        }
    }
    pub fn update_list(&mut self, index: usize, it: &Data) {
        if let Data::List(list) = self {
            list[index] = it.clone();
        }
    }
    pub fn is_list(&self) -> bool {
        matches!(self, Data::List(_))
    }
    pub fn is_string(&self) -> bool {
        matches!(self, Data::String(_))
    }
    pub fn is_empty_list(&self) -> bool {
        matches!(self, Data::List(list) if list.is_empty())
    }
    // TODO: 修改为引用类型
    pub fn get_list(&self) -> Option<Vec<Data>> {
        if let Data::List(list) = self {
            Some(list.clone())
        } else {
            None
        }
    }
    // TODO: 修改为引用类型
    pub fn get_map(&self) -> Option<HashMap<String, Data>> {
        if let Data::Object(map) = self {
            Some(map.clone())
        } else {
            None
        }
    }
    pub fn from_bool(b: bool) -> Self {
        Self::Bool(b)
    }
    pub fn from_num<T: Into<f64>>(n: T) -> Self {
        let n: f64 = n.into();
        Self::Number(n)
    }
    pub fn from_vec(v: &[Data]) -> Self {
        let list = v.to_vec();
        Self::List(list)
    }
}

impl FromStr for Data {
    type Err = ();

    fn from_str(s: &str) -> Result<Self, Self::Err> {
        let string = s.to_string();
        Ok(Self::String(string))
    }
}

impl From<String> for Data {
    fn from(value: String) -> Self {
        Self::String(value)
    }
}

impl From<&str> for Data {
    fn from(value: &str) -> Self {
        Self::String(value.to_string())
    }
}

impl From<i64> for Data {
    fn from(value: i64) -> Self {
        Self::Number(value as f64)
    }
}
impl From<i32> for Data {
    fn from(value: i32) -> Self {
        Self::Number(value as f64)
    }
}
impl From<i16> for Data {
    fn from(value: i16) -> Self {
        Self::Number(value as f64)
    }
}
impl From<i8> for Data {
    fn from(value: i8) -> Self {
        Self::Number(value as f64)
    }
}
impl From<u8> for Data {
    fn from(value: u8) -> Self {
        Self::Number(value as f64)
    }
}
impl From<u16> for Data {
    fn from(value: u16) -> Self {
        Self::Number(value as f64)
    }
}
impl From<u32> for Data {
    fn from(value: u32) -> Self {
        Self::Number(value as f64)
    }
}

impl FromPrimitive for Data {
    fn from_i64(n: i64) -> Option<Self> {
        Some(Self::Number(n as f64))
    }

    fn from_u64(n: u64) -> Option<Self> {
        if n > i64::MAX as u64 {
            None
        } else {
            Some(Self::Number(n as f64))
        }
    }
}

impl From<bool> for Data {
    fn from(value: bool) -> Self {
        Self::Bool(value)
    }
}
